﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

//引用折叠
/*
通过模板或 typedef 中的类型操作可以构成引⽤的引⽤时，这时C++11给出了⼀个引⽤折叠的规
则：右值引⽤的右值引⽤折叠成右值引⽤，所有其他组合均折叠成左值引⽤。
*/

typedef int& lref;
typedef int&& rref;

// 由于引用折叠限定，f1实例化以后总是一个左值引用
template<class T>
void f1(T& x)
{}

// 由于引用折叠限定，f2实例化后可以是左值引用，也可以是右值引用
// 万能引用
template<class T>
void f2(T&& x)
{}

//int main()
//{
//	int n = 0;
//	lref& r1 = n; // r1 的类型是 int&  左值引用叠加左值引用折叠为左值引用
//	lref&& r2 = n; // r2 的类型是 int&
//	rref& r3 = n; // r3 的类型是 int&
//	rref&& r4 = 1; // r4 的类型是 int&&  右值引用叠加右值引用折叠为右值引用
//
//	// 没有折叠->实例化为void f1(int& x)
//	f1<int>(n);  //显示实例化 T是int 只能传左值
//	//f1<int>(0); // 报错
//
//	// 折叠->实例化为void f1(int& x)
//	f1<int&>(n);
//	//f1<int&>(0); // 报错
//
//	// 折叠->实例化为void f1(int& x)
//	f1<int&&>(n);
//	//f1<int&&>(0); // 报错
//
//	// 折叠->实例化为void f1(const int& x)  const左值引用既可以接受左值也可以接受右值
//	f1<const int&>(n);
//	f1<const int&>(0);
//
//	// 折叠->实例化为void f1(const int& x)
//	f1<const int&&>(n);
//	f1<const int&&>(0);
//
//	// 没有折叠->实例化为void f2(int&& x)
//	//f2<int>(n); // 报错
//	f2<int>(0);
//
//	// 折叠->实例化为void f2(int& x)
//	f2<int&>(n);
//	//f2<int&>(0); // 报错
//
//	// 折叠->实例化为void f2(int&& x)
//	//f2<int&&>(n); // 报错
//	f2<int&&>(0);
//
//	return 0;
//}


 //万能引用
//template<class T>
//void Function(T&& t)
//{
//	int a = 0;
//	T x = a;
//	//x++;
//
//	cout << &a << endl;
//	cout << &x << endl << endl;
//}

//int main()
//{
//	// 10是右值，推导出T为int，模板实例化为void Function(int&& t)，不折叠
//	Function(10);//x和a的地址不一样 说明这里T没有推到成引用 因此没有折叠 不是int&&
//
//	int a;
//	// a是左值，推导出T为int&，引用折叠，模板实例化为void Function(int& t)
//	Function(a);
//
//	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)，不折叠
//	Function(std::move(a)); // 右值
//
//	const int b = 8;
//	// b是左值，推导出T为const int&，引用折叠，模板实例化为void Function(const int&t)
//	// 所以Function内部会编译报错，x不能++
//	Function(b); // const 左值
//
//	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&&t)
//	// 所以Function内部会编译报错，x不能++
//	Function(std::move(b)); // const 右值
//
//	return 0;
//}



void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

// 万能引用
template<class T>
void Function(T&& t)
{
	// 保持t的属性
	Fun(forward<T>(t));  //完美转发  完美转发（Perfect Forwarding）是一种能够保持函数参数原始类型（包括是否为左值或右值）的技术。
}

int main()
{
	// 10是右值，推导出T为int，模板实例化为void Function(int&& t)
	Function(10); // 右值  10是右值 t作为右值引用是一个左值 这样这个Function作为中间传递时就失去了原始传递值的属性

	int a;
	// a是左值，推导出T为int&，引用折叠，模板实例化为void Function(int& t)
	Function(a); // 左值

	// std::move(a)是右值，推导出T为int，模板实例化为void Function(int&& t)
	Function(std::move(a)); // 右值

	const int b = 8;
	// a是左值，推导出T为const int&，引用折叠，模板实例化为void Function(const int& t)
	Function(b);

	// std::move(b)右值，推导出T为const int，模板实例化为void Function(const int&& t)
	Function(std::move(b)); // const 右值

	return 0;
}
